<?php
/**
 * 杂质分析
 * Created by PhpStorm.
 * User: ZhangYinxian
 * Date: 2016-10-08
 * Time: 0:17
 */

namespace app\index\logic;

use think\Db;
class PeptideImpurity extends AminoSubject
{
    private $mImpurityType;
    private $mImpurityMessage = '';
    private $mImpurityResults = [];

    /**
     * @var int 固相树脂载体类型（1 Wang resin、2 CTC resin、3 MBHA resin、4 AM resin）
     */
    private $mCarrierType;
    /**
     * @var string 0 Boc法、1 Fmoc法
     */
    private $mSyntheticMethod;
    /**
     * @var float 分辨率：0.3高分辨率 1低分辨率
     */
    private $mN ;
    /**
     * @var int 是否有醋酸酐封端操作：是或否
     */
    private $mHasOperate = 0;
    /**
     * @var string 第几个氨基酸合成时采用了封端
     */
    private $mOperateLocation;
    /**
     * @var string 杂质分子量
     */
    private $mImpurityWeight;

    private $mDebug=false;

    public function getResult()
    {
        $result = parent::getResult();
        if ($result['hasError']){
            return $result;
        }

        $check_result = $this->checkCarrierType();
        if ($check_result['has_error']){
            $result['hasError'] = $check_result['has_error'];
            $result['message'] = $check_result['message'];
            return $result;
        }

        $impurity_result = $this->getImpurityData();
        if ($impurity_result['has_error']){
            $result['hasError'] = $impurity_result['has_error'];
            $result['message'] = $impurity_result['message'];
            return $result;
        }

        $result['impurity_type']=$this->mImpurityType;
        $result['impurity_message']=$this->mImpurityMessage;
        $result['impurity_results']=$this->getImpurityResults();
        $result['has_weight_result']=$impurity_result['has_weight_result'];
        $result['weights_message']=$impurity_result['weights_message'];
        $result['location_info'] = $this->getLocationInfo();

        return $result;
    }

    private function getLocationInfo(){
        $location_info = '';
        $all_locations = $this->mAminoLocations['0'];
        $all_locations_count = count($all_locations);
        $main_amino_locations = $all_locations['0'];
        $amino_locations_count = count($main_amino_locations);

        $location_info_list = [];

        $first_amino = $main_amino_locations[0]['full'];
        for($index=0; $index<$amino_locations_count; $index++){
            $location = $main_amino_locations[$index];
            $full = $location['full'];
            $single = $location['single'];
            if ($full=='Ac' || $full=='NH2'){
                $location_info = $full;
            }else{
                if ($first_amino=='Ac'){
                    $location_info = $full . '<sup>'.$index.'</sup>';
                }else {
                    $location_info = $full . '<sup>' . ($index + 1) . '</sup>';
                }
            }

            if ($all_locations_count>1){ // 存在侧链
                $key = $single. '-'. ($index+1);
                $tmp_locations = isset($all_locations[$key])?$all_locations[$key] : null;
                if (count($tmp_locations)>0){
                    $tmp_location_info_list = [];
                    foreach ($tmp_locations as $tmp_location){
                        array_push($tmp_location_info_list, $tmp_location['full']);
                    }
                    $location_info .= '('.implode('-',$tmp_location_info_list).')';
                }
            }
            array_push($location_info_list, $location_info);
        }
        $location_info = implode('-', $location_info_list);
        return $location_info;
    }

    /**
     * 数组结果转化为字符串结果
     * @return array 结果数组
     */
    private function getImpurityResults(){
        $impurity_results = $this->mImpurityResults;
        foreach ($impurity_results as $key=>$impurity_result){
             $detail = $impurity_result['detail'];
            foreach ($detail as $index=>$tmp_detail){
                $impurity_results[$key]['detail'][$index]['content'] = implode('; ', $tmp_detail['detail']);
            }
        }
        $this->mImpurityResults = $impurity_results;
        return array_values($impurity_results);
    }

    private function getImpurityData(){
        return $this->getCarrierTypeDetail();
    }

    /**
     * 分析载体类型是否正确
     * 1 Wang resin、2 CTC resin、3 MBHA resin、4 AM resin
     * @param $aminoSubject object 氨基酸序列对象
     */
    private function checkCarrierType(){
        $amino_subject = $this->mAminoSubject;
        $has_error = false;
        $message = '';

        $carrier_type = $this->mCarrierType;
        $last_amino_data = $this->getLastAminoData($amino_subject);
        if (is_null($last_amino_data)){
            $has_error = true;
            $message = '无法获取序列最后一个氨基酸';
            return [
                'has_error'=>$has_error,
                'message'=>$message
            ];
        }
        if ($carrier_type==1){
            $disallowed = ['NH2','Cys','His','Pro'];
            foreach ($disallowed as $item){
                if ($last_amino_data['single']==$item || $last_amino_data['full']==$item){
                    $has_error = true;
                    break;
                }
            }
            if ($has_error){
                $has_error = true;
                $message = '序列不符合载体Wang resin';
                return [
                    'has_error'=>$has_error,
                    'message'=>$message
                ];
            }
        }else if ($carrier_type==2){
            /**
             * 0 Boc法、1 Fmoc法
             */
            $synthetic_method = $this->mSyntheticMethod;
            if ($last_amino_data['single']=='NH2' || $synthetic_method==0){
                $has_error = true;
                $message = '序列不符合载体CTC resin';
                return [
                    'has_error'=>$has_error,
                    'message'=>$message
                ];
            }
        }else if ($carrier_type==3 || $carrier_type==4){
            $allowed = ['NH2','Asn','Gln'];
            $has_error = true;
            foreach ($allowed as $item){
                if ($last_amino_data['single']==$item || $last_amino_data['full']==$item){
                    $has_error = false;
                    break;
                }
            }
            $carrier_name = ($carrier_type==3) ? 'MBHA resin' : 'AM resin';
            $message = '序列不符合载体'.$carrier_name;
            return [
                'has_error'=>$has_error,
                'message'=>$message
            ];
        }

        return [
            'has_error'=>$has_error,
            'message'=>$message
        ];
    }
    /**
     * 获取主链中的最后一个氨基酸信息
     * @param $aminoSubject object 氨基酸序列对象
     * @return mixed|null array 氨基酸信息，包含single和full
     */
    private function getLastAminoData(){
        $amino_locations = $this->mAminoLocations;
        if (count($amino_locations)>0){
            $details = $amino_locations[0][0];
            if (is_array($details) && count($details)>0){
                return $details[count($details)-1];
            }
        }
        return null;
    }

    /**
     * 获取详细信息
     */
    private function getCarrierTypeDetail(){
        $impurity_weight = $this->mImpurityWeight;
        $impurity_weights = [];
        if (strlen($impurity_weight)>0){
            $impurity_weight = str_replace('\\',',', $impurity_weight);
            $impurity_weight = str_replace('/', ',', $impurity_weight);
            $impurity_weight = str_replace('，', ',', $impurity_weight);
            $impurity_weight = str_replace('；', ',', $impurity_weight);
            $impurity_weight = str_replace(';', ',', $impurity_weight);
            $impurity_weights = explode(',', $impurity_weight);
            foreach ($impurity_weights as $index=>$tmp_weight){
                $impurity_weights[$index] = trim($tmp_weight);
            }
            sort($impurity_weights);
        }

        // 计算分子量之间的关系
        $impurity_result = $this->calculateImpurities($impurity_weights);

        // 存放杂质类型结果
        $carrier_type_results = array();
        foreach ($impurity_weights as $tmp_impurity_weight){
            $tmp_impurity_weight = trim($tmp_impurity_weight);
            $carrier_type_results[$tmp_impurity_weight] = [
                'key'=>$tmp_impurity_weight,
                'detail'=>[],
                'has_result'=>false
            ];
            //共6种杂质类型
            for($index=0; $index<6; $index++){
                $carrier_type_results[$tmp_impurity_weight]['detail'][$index] = [
                    'detail'=>[],
                    'content'=>''
                ];
            }
            $result = $this->getSingleCarrierTypeDetail($tmp_impurity_weight, $carrier_type_results);
            if ($result['has_error']){
                return $result;
            }
        }
        $this->mImpurityResults = $carrier_type_results;

        return [
            'has_error'=>false,
            'message'=>'',
            'has_weight_result'=>$impurity_result['has_weight_result'],
            'weights_message'=>implode(';', $impurity_result['weights_message'])
        ];
    }

    private function calculateImpurities(&$impurityWeights){
        $has_weight_result = false;
        $weights_message = [];

        $impurity_weights_count = count($impurityWeights);
        if ($impurity_weights_count>1){

            $impurity_weights_count -= 1;
            rsort($impurityWeights);
            $amino_locations = $this->mAminoLocations['0']['0'];
            $amino_locations_count = count($amino_locations);
            $standard_data = $this->mChemicalData['standard_data'];
            $const_data = $this->mChemicalData['const_data'];
            $n = $this->mN;
            $has_result = false;
            for($amino_length=1; $amino_length<=3; $amino_length++){
                if ($has_result && !$this->mDebug){
                    break;
                }
                for ($index=0; $index<$impurity_weights_count; $index++){
                    $weight_1 = $impurityWeights[$index];
                    $weight_2 = $impurityWeights[$index+1];
                    $value = $weight_1 - $weight_2;
                    if ($amino_length==1){
                        foreach ($amino_locations as $amino_location){
                            $single = $amino_location['single'];
                            $data = $standard_data[$single];
                            $tmp_mw = $this->getAminoMW($data, $const_data);
                            $result_value = $value - $tmp_mw;
                            //var_dump("$result_value>=-$n && $result_value<=$n");
                            if ($result_value>=-$n && $result_value<=$n){
                                $has_weight_result = true;
                                array_push($weights_message, '分子量'.$weight_2.'的杂质比分子量'.$weight_1."的杂质少一个$single");
                                $has_result = true;
                            }
                        }
                    }else{

                        $flags = [];
                        for($index=0; $index<$amino_locations_count; $index++){
                            if ($index<$amino_length){
                                $flags[$index]=1;
                            }else{
                                $flags[$index]=0;
                            }
                        }
                        $new_amino_location_result = $this->getNewAminoLocation($amino_locations, $flags, $standard_data, $const_data);
                        $result_value = $value - $new_amino_location_result['residue_weight'];
                        if ($result_value>=-$n && $result_value<=$n){
                            $has_weight_result = true;
                            array_push($weights_message, '分子量'.$weight_2.'的杂质比分子量'.$weight_1.'的杂质少一个'.$new_amino_location_result['single']);
                            $has_result = true;
                        }
                        if (!$has_result && $this->mDebug){
                            $combine_number = combine_number($amino_locations_count, $amino_length);
                            for($index=1; $index<$combine_number; $index++){
                                $flags = $this->changeFlags($flags);
                                $new_amino_location_result = $this->getNewAminoLocation($amino_locations, $flags, $standard_data, $const_data);
                                $result_value = $value - $new_amino_location_result['residue_weight'];
                                if ($result_value>=-$n && $result_value<=$n){
                                    $has_weight_result = true;
                                    array_push($weights_message, '分子量'.$weight_2.'的杂质比分子量'.$weight_1.'的杂质少一个'.$new_amino_location_result['single']);
                                    $has_result = true;
                                    if ($has_result && !$this->mDebug){
                                        break;
                                    }
                                }
                            }
                        }

                    }
                }
            }

        }

        return [
            'has_weight_result'=>$has_weight_result,
            'weights_message'=>$weights_message
        ];
    }
    private function getSingleCarrierTypeDetail($impurityWeight, &$carrierTypeResults){
        $mw = $this->mAminoSubject->mMw;
        $n = $this->mN;
        // 杂质类型1计算 双倍体杂质
        $impurity_result = $impurityWeight - 2*$mw;
        if ($impurity_result>=(-2-$n) && $impurity_result<=$n){
            $this->pushCarrierTypeResult($carrierTypeResults, $impurityWeight, 0, '是');
        }else{
            $this->pushCarrierTypeResult($carrierTypeResults, $impurityWeight, 0, '否', false);
        }

        if ($impurity_result>=(20-$n) && $impurity_result<=(20+$n)){
            $this->pushCarrierTypeResult($carrierTypeResults, $impurityWeight, 0, '双倍体加钠盐');
        }

        // 杂质类型2计算 缺失或重复杂质
        $impurity_result = $impurityWeight - $mw;
        $this->calculateCarrierTypeOfShortAndRepeat($impurityWeight, $impurity_result, $carrierTypeResults);

        // 杂质类型3计算, 封端杂质，必须在选择了有封端的情况才计算
        $has_operate = $this->mHasOperate;
        if ($has_operate==1){
           $result = $this->calculateCarrierTypeOfEndCapping($impurityWeight, $carrierTypeResults);
            if ($result['has_error']){
                return $result;
            }

            $result = $this->calculateCarrierTypeOfECAndSR($impurityWeight, $carrierTypeResults);
        }
        //杂质类型5计算， 杂质5：副反应杂质
        $this->calculateCarrierTypeOfReaction($impurityWeight, $carrierTypeResults);

        //杂质类型6计算，杂质6：误用杂质
        $this->calculateCarrierTypeOfWrongAmino($impurityWeight, $carrierTypeResults);
        return [
            'has_error'=>false,
            'message'=>''
        ];
    }

    /**
     * 计算杂质类型2 缺失或重复杂质
     * @param $impurityWeight string 杂质分子量
     * @param $impurityResult int 差值
     * @param $carrierTypeResults array 结果
     * @param int $aminoLength 每次分析的残基个数
     */
    private function calculateCarrierTypeOfShortAndRepeat($impurityWeight, $impurityResult, &$carrierTypeResults, $aminoLength=1, $carrierType=1, $aminoLocations=null, $operateLocation=null){
        $n = $this->mN;
        $residue_result = $this->getMaxOrMinResidue($aminoLength, $aminoLocations);
        $min_residue_value = $residue_result['min_residue']['value'];
        $amino_locations = is_null($aminoLocations) ? $this->mAminoLocations['0']['0'] : $aminoLocations;

        if(count($aminoLocations)>0){
            $tmp_amino_locations = $aminoLocations;
            $aminoLocations = [];
            foreach ($tmp_amino_locations as $tmp_amino_location){
                if ($tmp_amino_location['single']!='NH2'){
                    array_push($aminoLocations, $tmp_amino_location);
                }
            }
        }

        $impurity_result_abs = abs($impurityResult);
        //var_dump("$impurity_result_abs>($max_residue_value+$n)=".($impurity_result_abs>($max_residue_value+$n)));
        //var_dump($residue_result);
        //var_dump("$impurity_result_abs>=$min_residue_value && $impurity_result_abs<=$max_residue_value");
        /**
         * 当差值的绝对值大于等于 最小残基-n 则， 需要比较各残基的值
         * 否者就返回
         */
        if ($impurity_result_abs>=($min_residue_value-$n) ){
            // 只计算主链上的
            $standard_data = $this->mChemicalData['standard_data'];

            if ($aminoLength==1){
                $amino_details = [];
                foreach ($amino_locations as $amino_location){
                    $single = $amino_location['single'];
                    if (isset($amino_details[$single])){
                        //$amino_details[$single]['count']++;
                    }else{
                        $amino_details[$single]['count'] = 1;
                    }
                }

                foreach ($amino_details as $single=>$amino_detail){
                    $tmp_standard_data = $standard_data[$single];
                    $residue_weight = $tmp_standard_data['residue_weight'];
                    $tmp_value = abs($impurity_result_abs - $residue_weight);

                    if ($tmp_value>=-$n && $tmp_value<=$n){
                        $count = $amino_detail['count'];
                        if ($impurityResult<0){
                            if($count>1){
                                $message = '缺失'.$count.'个'.$single.'氨基酸';
                            }else{
                                $message = '缺失'.$single.'氨基酸';
                            }

                        }else{
                            if ($count>1){
                                $message = '重复连接'.$count.'个'.$single.'氨基酸';
                            }else{
                                $message = '重复连接'.$single.'氨基酸';
                            }

                        }
                        if (!is_null($operateLocation)){
                            $message = $operateLocation.'号位封端且'.$message;
                        }
                        $this->pushCarrierTypeResult($carrierTypeResults, $impurityWeight, $carrierType, $message);
                    }
                }
                if (($aminoLength+1)<=3){
                    $this->calculateCarrierTypeOfShortAndRepeat($impurityWeight, $impurityResult, $carrierTypeResults, $aminoLength+1, $carrierType, $amino_locations, $operateLocation);
                }
            }else{
                $amino_locations_count = count($amino_locations);
                $flags = [];
                for($index=0; $index<$amino_locations_count; $index++){
                    if ($index<$aminoLength){
                        $flags[$index]=1;
                    }else{
                        $flags[$index]=0;
                    }
                }

                $const_data = $this->mChemicalData['const_data'];

                $combine_number = combine_number($amino_locations_count, $aminoLength);

                $compile_result = [];
                for($index=0; $index<$combine_number; $index++){
                    if ($index>0){
                        $flags = $this->changeFlags($flags);
                    }
                    $flag_result = $this->getNewAminoLocation($aminoLocations, $flags, $standard_data, $const_data);
                    $tmp_value = abs($impurity_result_abs - $flag_result['residue_weight']);
                    if ($tmp_value>=-$n && $tmp_value<=$n){
                        //$tmp_single = $flag_result['single'];
                        $amino_string = $flag_result['amino_string'];
                        if (in_array($amino_string, $compile_result)){
                            continue;
                        }
                        array_push($compile_result, $amino_string);
                        if ($impurityResult<0){
                            $message = '缺失'.$flag_result['single'].'氨基酸';
                        }else{
                            $message = '重复连接'.$flag_result['single'].'氨基酸';
                        }
                        if (!is_null($operateLocation)){
                            $message = $operateLocation.'号位封端且'.$message;
                        }
                        $this->pushCarrierTypeResult($carrierTypeResults, $impurityWeight, $carrierType, $message);
                    }
                }
                if (($aminoLength+1)<=3){
                    $this->calculateCarrierTypeOfShortAndRepeat($impurityWeight, $impurityResult, $carrierTypeResults, $aminoLength+1, $carrierType, $amino_locations, $operateLocation);
                }
            }
        }
        return;
    }

    /**
     * 类型3 封端杂质，编号2, endCapping
     * @param $impurityWeight
     * @param $mw
     * @param $n
     * @param $carrierTypeResults array 结果
     * @param $carrierType int 2
     * @return array
     */
    private function calculateCarrierTypeOfEndCapping($impurityWeight, &$carrierTypeResults, $carrierType=2){
        $n = $this->mN;
        $amino_locations = $this->mAminoLocations['0']['0'];

        // 如果c端为flag=2的氨基酸，需要去除
        $first_amino_location = $amino_locations[0];
        $standard_data = $this->mChemicalData['standard_data'];
        if (isset($standard_data[$first_amino_location['single']])){
            $first_amino_data = $standard_data[$first_amino_location['single']];
            if ($first_amino_data['flag']==2){
                $amino_locations = array_slice($amino_locations, 1);
            }
        }

        $ac_data = $standard_data['Ac'];

        $const_data = $this->mChemicalData['const_data'];
        $amino_locations_count = count($amino_locations);
        for($index=0; $index<$amino_locations_count; $index++){
            $new_aminos = array_slice($amino_locations, $index );
            $weight = $this->getAminoMW($ac_data, $const_data);//$ac_data['residue_weight'];
            $aminos = 'Ac-';
            foreach ($new_aminos as $new_amino){
                $single = $new_amino['single'];
                $data = $standard_data[$single];
                $weight += $this->getAminoMW($data, $const_data);//$data['residue_weight'];
                $aminos = $aminos.$single;
            }
            $weight += $this->getH2OMW($const_data);
            $value = $impurityWeight - $weight;
            //var_dump("$impurityWeight - $weight=".$value);
            if ($value>=-$n && $value<=$n){
                $this->pushCarrierTypeResult($carrierTypeResults, $impurityWeight, $carrierType, '杂质序列为：'.$aminos);
            }
        }

        return [
            'has_error'=>false,
            'message'=>''
        ];
    }

    /**
     * 杂质类型4，封端和重复缺失杂质
     */
    private function calculateCarrierTypeOfECAndSR($impurityWeight, &$carrierTypeResults, $carrierType=3){
        $amino_locations = $this->mAminoLocations['0']['0'];

        // 如果c端为flag=2的氨基酸，需要去除
        $first_amino_location = $amino_locations[0];
        $standard_data = $this->mChemicalData['standard_data'];
        if (isset($standard_data[$first_amino_location['single']])){
            $first_amino_data = $standard_data[$first_amino_location['single']];
            if ($first_amino_data['flag']==2){
                $amino_locations = array_slice($amino_locations, 1);
            }
        }

        // 特殊位置信息，用于封端杂质的计算
        $special_amino_locations = [];
        $operate_location = $this->mOperateLocation;

        if (strlen($operate_location)>0){
            $operate_locations = explode(',', $operate_location);
            foreach ($operate_locations as $index=>$tmp_location){
                if (is_numeric(trim($tmp_location))){
                    if($tmp_location>count($amino_locations)){
                        return [
                            'has_error'=>true,
                            'message'=>'封端位置过大，请重新输入'
                        ];
                    }
                    $operate_locations[$index] = trim($tmp_location);
                    array_push($special_amino_locations, array_slice($amino_locations, $tmp_location));
                }else{
                    return [
                        'has_error'=>true,
                        'message'=>'封端位置输入有误，请重新输入'
                    ];
                }
            }
        }

        $special_amino_locations_count = count($special_amino_locations);
        if ($special_amino_locations_count>0){
            foreach ($special_amino_locations as $index=>$special_amino_location){
                $special_amino_location = array_merge([['single'=>'Ac','full'=>'Ac']], $special_amino_location);
                $special_mw = $this->getSpecialMW($special_amino_location);

                $impurity_result = $impurityWeight - $special_mw;
                $amino_length = 1;
                $current_operate_location = isset($operate_locations) ? $operate_locations[$index] : null;
                if(count($special_amino_location)>0){
                    $tmp_location = $special_amino_location;
                    $special_amino_location = [];
                    foreach ($tmp_location as $location){
                        if ($location['single']!='Ac'){
                            array_push($special_amino_location, $location);
                        }
                    }
                }
                $this->calculateCarrierTypeOfShortAndRepeat($impurityWeight, $impurity_result, $carrierTypeResults, $amino_length, $carrierType, $special_amino_location, $current_operate_location );
            }
        }

        return [
            'has_error'=>false,
            'message'=>''
        ];
    }

    /**
     * 杂质类型5，副反应杂质
     * @param $impurityWeight
     * @param $carrierTypeResults
     */
    private function calculateCarrierTypeOfReaction($impurityWeight, &$carrierTypeResults, $carrierType=4){
        $mw = $this->mAminoSubject->mMw;
        $n = $this->mN;
        $impurity_result = $impurityWeight-$mw;
        $min = $impurity_result - $n;
        $max = $impurity_result + $n;
        $amino_side_reactions = Db::table('amino_side_reaction')->where("value>=$min and value<=$max")->select();

        if (count($amino_side_reactions)>0){
            foreach ($amino_side_reactions as $amino_side_reaction){
                $valid = $this->checkCarrierTypeOfReactionCondition($amino_side_reaction);
                if ($valid){
                    $this->pushCarrierTypeResult($carrierTypeResults, $impurityWeight, $carrierType, $amino_side_reaction['result']);
                }
            }
        }
    }

    /**
     * 计算类型6，类型6：氨基酸使用错误杂质
     */
    private function calculateCarrierTypeOfWrongAmino($impurityWeight, &$carrierTypeResults, $carrierType=5){
        $mw = $this->mAminoSubject->mMw;
        $n = $this->mN;
        $impurity_result = $impurityWeight-$mw;
        $min = $impurity_result - $n;
        $max = $impurity_result + $n;
        $amino_wrong_datas = Db::table('amino_wrong_data')->where("value>=$min and value<=$max")->select();
        $amino_details = $this->mAminoSubject->mAminoDetails;
        if(count($amino_wrong_datas)>0){
            foreach ($amino_wrong_datas as $amino_wrong_data){
                $original = $amino_wrong_data['original'];
                $wrong = $amino_wrong_data['wrong'];
                if (isset($amino_details[$original])){
                    $detail = $amino_details[$original];
                    $message = $original.'可能误用为'.$wrong;
                    $this->pushCarrierTypeResult($carrierTypeResults, $impurityWeight, $carrierType, $message);
                    // 当序列中有当前的氨基酸有多个时，需要比对2-n个的值
                    $detail_count = $detail['count'];
                    if ($detail_count>1){
                       for($index=2; $index<=$detail_count; $index++){
                           $value_min = $amino_wrong_data['value']*$index-$n;
                           $value_max = $amino_wrong_data['value']*$index+$n;
                           $amino_wrong_data2 = Db::table('amino_wrong_data')->where("value>=$value_min and value<=$value_max")->select();
                           if(count($amino_wrong_data2)>0){
                               foreach ($amino_wrong_data2 as $data2){
                                   if($data2['original']==$original){
                                       $message = $index. '个'.$original.'可能误用为'.$data2['wrong'];
                                       $this->pushCarrierTypeResult($carrierTypeResults, $impurityWeight, $carrierType, $message);
                                   }

                               }
                           }
                       }
                    }

                }
            }
        }
    }

    /**
     * 检查给出的条件是否满足
     * @param $aminoSideReaction array 副反应杂质条件信息
     * @return bool true 满足条件， false不满足条件
     */
    private function checkCarrierTypeOfReactionCondition($aminoSideReaction){
        $condition_type = $this->replaceSpecial($aminoSideReaction['condition_type']);
        $condition_1 = $this->replaceSpecial($aminoSideReaction['condition1']);
        $condition_2 = $this->replaceSpecial($aminoSideReaction['condition2']);

        $condition = [
            'condition1'=>$condition_1,
            'condition2'=>$condition_2
        ];

        if ($condition_type=='empty'){
            return true;
        }

        $condition_types = explode(';', $condition_type);
        $is_valids = [];
        $is_valid = false;
        $data_list = [];

        foreach ($condition_types as $tmp_condition_type){
            $amino_locations = $this->mAminoLocations['0']['0'];
            switch (strtolower($tmp_condition_type)){
                case 'contain':
                    $amino_locations = $this->mAminoLocations['0'];
                    $is_valid = ImpurityConditionUtil::contain($amino_locations, $condition);
                    break;
                case 'cyclo':
                    $is_valid = ImpurityConditionUtil::cyclo($amino_locations, $condition);
                    break;
                case 'cyclo_enable':
                    $data_list['standard_data']=$this->mChemicalData['standard_data'];
                    $is_valid = ImpurityConditionUtil::cycloEnable($amino_locations, $condition, $data_list);
                    break;
                case 'cys_2':
                    $data_list['cys_locations']=$this->mCysLocations;
                    $is_valid = ImpurityConditionUtil::cys2($condition, $data_list);
                    break;
                case 'nterm':
                    $is_valid = ImpurityConditionUtil::nterm($amino_locations, $condition);
                    break;
                case 'cterm':
                    $is_valid = ImpurityConditionUtil::cterm($amino_locations, $condition);
                    break;
                case 'acid':
                    $data_list['acid_count']=$this->mAminoSubject->mAcidCount;
                    $is_valid = ImpurityConditionUtil::acid($amino_locations, $condition, $data_list);
                    break;
                case 'carrier_type':
                    $data_list['carrier_type']=$this->mCarrierType;
                    $is_valid = ImpurityConditionUtil::carrierType($condition, $data_list);
                    break;
                case 'synthetic_method':
                    $data_list['synthetic_method']=$this->mSyntheticMethod;
                    $is_valid = ImpurityConditionUtil::synthetic_method($condition, $data_list);
                    break;
            }
            array_push($is_valids, $is_valid);
        }

        if (count($is_valids)>0){
            $tmp_valid = true;
            foreach ($is_valids as $tmp_is_valid){
                $is_valid = $tmp_valid && $tmp_is_valid;
            }
        }
        return $is_valid;
    }

    private function getSpecialMW($specialAminoLocations){
        $mw = 0;
        $standard_data = $this->mChemicalData['standard_data'];
        $const_data = $this->mChemicalData['const_data'];
        foreach ($specialAminoLocations as $amino_location){
            $single = $amino_location['single'];
            $single_data = $standard_data[$single];
            $mw += $this->getAminoMW($single_data, $const_data); //$single_data['residue_weight'];
        }
        $mw += $this->getH2OMW($const_data);
        return $mw;
    }

    private function getAminoMW($aminoData, $constData){
        $mw = 0;
        $element_index = $this->mElementIndex;
        foreach ($element_index as $element){
            $element = strtolower(trim($element));
            $mw += $aminoData[$element] * $constData[$element]['mw'];
        }
        return $mw;
    }

    /**
     * 获取水的平均分子量
     * @param $constData
     * @return int 水的平均分子量
     */
    private function getH2OMW($constData){
        $mw = 0;
        $mw += $constData['h']['mw'] * 2;
        $mw += $constData['o']['mw'];
        return $mw;
    }

    /**
     * 根据获取氨基酸长度计算残基的最大和最小值,只求出数字
     * @param int $aminoLength 氨基酸个数，默认为1,根据此进行组合
     * @return array 返回大小值
     */
    private function getMaxOrMinResidue($aminoLength=1, $aminoLocations=null, $chain='0'){
        $amino_locations = is_null($aminoLocations) ? $this->mAminoSubject->mAminoLocation[$chain] : $aminoLocations;

        $max_residue = ['single'=>'', 'value'=>0];
        $min_residue = ['single'=>'', 'value'=>0];
        $chemical_data = $this->mChemicalData;
        $standard_data = $chemical_data['standard_data'];
        $const_data = $chemical_data['const_data'];

        if ($aminoLength==1){
            foreach ($amino_locations as $index=>$amino_location){
                $single = $amino_location['single'];
                $single_data = $standard_data[$single];
                $residue_weight = $this->getAminoMW($single_data, $const_data);

                if ($index==0){
                    $min_residue = ['single'=>$single, 'value'=>$residue_weight];
                    $max_residue = $min_residue;
                }else{
                    $min_value = $min_residue['value'];
                    $max_value = $max_residue['value'];
                    if ($residue_weight<$min_value){
                        $min_residue = ['single'=>$single, 'value'=>$residue_weight];
                    }
                    if ($residue_weight>$max_value){
                        $max_residue = ['single'=>$single, 'value'=>$residue_weight];
                    }
                }
            }

        }else{
            $amino_locations_count = count($amino_locations);
            $flags = [];
            for($index=0; $index<$amino_locations_count; $index++){
                if ($index<$aminoLength){
                    $flags[$index]=1;
                }else{
                    $flags[$index]=0;
                }
            }
            $flag_result = $this->getFlagResult($amino_locations, $flags, $standard_data, $const_data, $min_residue, $max_residue);
            $min_residue = $flag_result['min_residue'];
            $max_residue = $flag_result['max_residue'];

            $combine_number = combine_number($amino_locations_count, $aminoLength);
            for($index=1; $index<$combine_number; $index++){
                $flags = $this->changeFlags($flags);

                $flag_result = $this->getFlagResult($amino_locations, $flags, $standard_data, $const_data, $min_residue, $max_residue);
                $min_residue = $flag_result['min_residue'];
                $max_residue = $flag_result['max_residue'];
            }
        }

        return [
            'min_residue'=>$min_residue,
            'max_residue'=>$max_residue
        ];

    }

    private function changeFlags($flags){
        $flags_count = count($flags);
        $pos = 0;
        for($i=0; $i<$flags_count; $i++){
            $flag1 = $flags[$i];
            $flag2 = $flags[$i+1];
            if ($flag1==1 && $flag2==0){
                $flags[$i] = 0;
                $flags[$i+1]=1;
                $pos = $i;
                break;
            }
        }
        $sum = 0;
        for($i=0; $i<$pos; $i++){
            if($flags[$i]==1){
                $sum ++;
            }

        }
        for($i=0; $i<$pos; $i++){
            if($i<$sum){
                $flags[$i]=1;
            }else{
                $flags[$i]=0;
            }
        }
        return $flags;
    }
    private function getFlagResult($aminoLocations, $flags, $standardData, $constData, $minResidue, $maxResidue){
        $aminos = '';
        $weight = 0;
        foreach ($flags as $index=>$flag){
            if ($flag==0) continue;
            $amino_location = $aminoLocations[$index];
            $single = $amino_location['single'];
            $data = $standardData[$single];
            $weight += $this->getAminoMW($data, $constData);
            $aminos.=$single;
        }
        if($weight <= $minResidue['value']){
            $minResidue['value'] = $weight;
            $minResidue['single']=$aminos;
        }
        if($weight >= $maxResidue['value']){
            $maxResidue['value'] = $weight;
            $maxResidue['single'] = $aminos;
        }

        return [
            'min_residue'=>$minResidue,
            'max_residue'=>$maxResidue
        ];
    }

    /**
     * 根据flags的1的情况，重新获取新的aminoLocation信息
     * @param $aminoLocations array 氨基酸位置信息
     * @param $flags array 组合标记数组
     * @param $standardData array 基础氨基酸信息
     * @param $constData array 元素分子量信息
     * @return array 结果，返回single和residue_weight
     */
    private function getNewAminoLocation($aminoLocations, $flags, $standardData, $constData){
        $weight = 0;
        $amino_sequence = '';
        $aminos = [];
        $flag_count = count($flags);
        for ($index=0; $index<$flag_count; $index++){
            $flag = $flags[$index];
            if ($flag==1 && isset($aminoLocations[$index])){
                $amino_location = $aminoLocations[$index];
                $single = $amino_location['single'];
                $data = $standardData[$single];
                $weight += $this->getAminoMW($data, $constData);
                $amino_sequence.=$single;
                if (strlen($single)>1 && $index<($flag_count-1)){
                    $amino_sequence.='-';
                }
                array_push($aminos, $single);
            }
        }
        asort($aminos);
        $amino_string = implode('', $aminos);
        return ['single'=>$amino_sequence, 'residue_weight'=>$weight, 'amino_string'=>$amino_string];
    }

    /**
     * 加入结果到结果数组中
     * @param $carrierTypeResults array 结果数组
     * @param $impurityWeight string 杂质分子量
     * @param $carrierType int 结果类别 0 1 2 3 4 5
     * @param $message string 输出的内容
     */
    private function pushCarrierTypeResult(&$carrierTypeResults, $impurityWeight, $carrierType, $message, $hasResult = true){
        $carrierTypeResults[$impurityWeight]['has_result'] = $hasResult;
        array_push($carrierTypeResults[$impurityWeight]['detail'][$carrierType]['detail'], $message);
    }

    /**
     * 转换特殊符号
     * @param $original string 原始字符串
     * @param null $fromStr string|array 需要转换的字符，支持单个和字符数组
     * @param null $destStr string 目标字符串成
     * @return mixed|string 转换后的字符串
     */
    private function replaceSpecial($original, $fromStr=null, $destStr=null){
        if (is_null($original)) return $original;
        $original = trim($original);
        if (strlen($original)==0) return $original;
        if (is_null($fromStr) && is_null($destStr)){
            $original = str_replace('；',';', $original);
            $original = str_replace('，',',', $original);
            $original = str_replace('（','(',$original);
            $original = str_replace('）',')', $original);
        }else if(is_null($fromStr) && !is_null($destStr)){
            $original = str_replace('；',$destStr, $original);
            $original = str_replace('，',$destStr, $original);
            $original = str_replace('（',$destStr,$original);
            $original = str_replace('）',$destStr, $original);
        }else{
            if (is_array($fromStr)){
                foreach ($fromStr as $from){
                    $original = str_replace($from, $destStr, $original);
                }
            }else if(is_string($fromStr)){
                $original = str_replace($fromStr, $destStr, $original);
            }
        }

        return $original;
    }



    public function __set($name, $value){
        parent::__set($name, $value);
        $this->$name = $value;
    }

    public function __get($name){
        return parent::__get($name);
    }
}